//作者：布衣前端 https://www.bilibili.com/read/cv13814623/ 出处：bilibili
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import { ElMessage } from 'element-plus';
import common from '/@/common/common'
import JSONbig from 'json-bigint'

// 接口类型和方法
interface BaseType{
    baseURL:string;
    getConfigParams():any;
    interceptors(instance:AxiosInstance, url: string | number | undefined):any;
    request(options: AxiosRequestConfig):any;
}

interface AxiosRequestType {
    baseURL?: string;
    url?: string|undefined;
    data?: any;
    params?: any;
    method?: string;
    headers?: any;
    timeout?: number;
    value?: any
    cancelToken?: any
}

// 取消重复请求
const CancelToken = axios.CancelToken
// 用于存储每个请求的取消函数以及对应标识
let sources:any = []

// 取消函数
let removeSource = (config:any)=>{
    for(let item in sources){
        if(sources[item].umet === config.url+"&"+config.method){
            sources[item].cancel('已取消重复请求，请勿重复请求')
            sources.splice(item, 1)
        }
    }
}

class AxiosHttpRequest implements BaseType{
    baseURL: string;
    timeout: number;
    constructor(){
        this.baseURL = import.meta.env.VITE_APP_BASE_API
        this.timeout = 15000
    }
    // 配置参数
    getConfigParams(){
        const config = {
            baseURL: this.baseURL,
            timeout: this.timeout,
            headers:{}
        }
        return config;
    }
    getConfigParamsNoTimeOut(){
        const config = {
            baseURL: this.baseURL,
            headers:{}
        }
        return config;
    }
    // 拦截设置
    interceptors(instance:AxiosInstance){
        // 请求拦截
        instance.interceptors.request.use((config: AxiosRequestType) =>{
            // 取消重复请求
            // removeSource(config)
            // config.cancelToken = new CancelToken(c =>{
            //     // 将取消函数存起来
            //     sources.push({ umet: config.url+'&'+config.method, cancel: c })
            // })
            // 添加全局的loading..
            // 请求头携带token
            // config.headers['Authorization'] = 'Bearer ' + 'token666'
            if(typeof config.headers['Content-Type'] == 'undefined') {
                config.headers['Content-Type'] = 'application/json;charset=utf-8'
            }
            // get请求映射params参数
            if (config.method === 'get' && config.params) {
                let url = config.url + '?';
                for (const propName of Object.keys(config.params)) {
                    const value = config.params[propName];
                    var part = encodeURIComponent(propName) + "=";
                    if (value !== null && typeof(value) !== "undefined") {
                        if (typeof value === 'object') {
                            for (const key of Object.keys(value)) {
                                let params = propName + '[' + key + ']';
                                var subPart = encodeURIComponent(params) + "=";
                                url += subPart + encodeURIComponent(value[key]) + "&";
                            }
                        } else {
                            url += part + encodeURIComponent(value) + "&";
                        }
                    }
                }
                url = url.slice(0, -1);
                config.params = {};
                config.url = url;
            }
            return config
        }, (error:any)=>{
            return Promise.reject(error)
        })

        // 响应拦截
        instance.interceptors.response.use((res:any) =>{
            // 取消重复请求
            removeSource(res.config)

            const code = res.status;
            // 获取错误信息
            let msg = res.statusText || ""
            switch (code) {
                case "401":
                    msg = '认证失败，无法访问系统资源'
                    break;
                case "403":
                    msg = '当前操作没有权限'
                    break;
                case "404":
                    msg = '访问资源不存在'
                    break;
                default:
                    msg = '未知错误，请联系管理员'
            }
            if(code >= 200 && code < 300){
                return Promise.resolve(res)
            }else{
                ElMessage.error(msg)
                return Promise.reject(res)
            }
        }, (error:any) =>{
            let { message } = error;
            if (message == "Network Error") {
                message = "后端接口连接异常";
            }
            else if (message.includes("timeout")) {
                message = "系统接口请求超时";
            }
            else if (message.includes("Request failed with status code")) {
                message = "系统接口" + message.substr(message.length - 3) + "异常";
            }
            ElMessage.error({
                showClose: true,
                message: message,
                duration: 5 * 1000
            })
            return Promise.reject(error)
        })
    }

    /**
     * 外部调用方法
     * @param options axios请求参数
     * @returns 实例
     */
    async request(options: AxiosRequestConfig){
        const instance = axios.create({
            // `transformResponse` 在传递给 then/catch 前，允许修改响应数据
			transformResponse: [function(data) {
				try {
		        // 作用1：把json字符串转为js对象
      	        // 作用2：把里面的大数字做安全处理
						return JSONbig.parse(data)
					} catch (e) {
						return data
					}
				}]
        });
        if(common.objectAvailable(options.headers) && options.headers['Content-Type']=='multipart/form-data'){
            options = Object.assign(this.getConfigParamsNoTimeOut(), options)
        } else {
            options = Object.assign(this.getConfigParams(), options)
        }
        this.interceptors(instance)
        return instance(options)
    }
}

// 实例化请求类
const http = new AxiosHttpRequest();

export default http;